#include <ArduinoJson.h>
#include <RTClib.h>
RTC_DS1307 RTC;
StaticJsonDocument<200> sendJson;          // 创建JSON对象，用来向树莓派发送数据
StaticJsonDocument<200> readJson;          // 创建JSON对象，用来存放接收到的数据
unsigned long lastUpdateTime = 0;          //记录上次上传数据时间
const unsigned long updateInterval = 2500; // 数据上传间隔时间2.5秒
int ID = 23;                               // 定义设备ID号

#include <Servo.h>
Servo myservo;
unsigned int pos = 0;

#include <SoftwareSerial.h>

//串口屏模块串口
SoftwareSerial mySerial2(6, 7);
//语音合成模块串口
SoftwareSerial mySerial1(8, 9);


//GY906红外测温部分定义
#include <Wire.h>
#include <Adafruit_MLX90614.h>

Adafruit_MLX90614 mlx = Adafruit_MLX90614();



//心率传感器相关部分
#include "MAX30105.h"
#include "heartRate.h"

MAX30105 particleSensor;

const byte RATE_SIZE = 4; //Increase this for more averaging. 4 is good.
byte rates[RATE_SIZE]; //Array of heart rates
byte rateSpot = 0;
long lastBeat = 0; //Time at which the last beat occurred
int lastValue = 0;
float beatsPerMinute;
int beatAvg;
long delta = 0;

//语音识别部分相关定义
#include <string.h>


unsigned char utf8str[40];
unsigned int Temp;
unsigned int tem;
unsigned int tem_1;
unsigned int tem_2;


//烟雾传感器蜂鸣器部分相关定义
#define GAS       4
#define BUZZER    5
unsigned int state;

#define servo_1 10
#define servo_2 11
#define servo_3 12

int Hour_1 = 0;
int Hour_2 = 0;
int Hour_3 = 0;
int Min_1 = 0;
int Min_2 = 0;
int Min_3 = 0;
float TC;
int speakFlag = 1;
int First = 0;
int Second = 0;
int Third = 0;
void setup () {
  mySerial1.begin(9600);
  mySerial2.begin(9600);
  Serial.begin(9600);
  attachInterrupt(0, stateChange, RISING);
  //心率传感器
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  {
    Serial.println("MAX30105 was not found. Please check wiring/power. ");
    while (1);
  }
  Serial.println("Place your index finger on the sensor with steady pressure.");

  particleSensor.setup(); //Configure sensor with default settings
  particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
  particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED

  //红外测温初始化
  Wire.begin();
  mlx.begin();

  RTC.begin();
  // following line sets the RTC to the date & time this sketch was compiled
  RTC.adjust(DateTime(__DATE__, __TIME__));


  pinMode(GAS, INPUT);
  pinMode(BUZZER, OUTPUT);

  pinMode(servo_1, OUTPUT);
  pinMode(servo_2, OUTPUT);
  pinMode(servo_3, OUTPUT);
  delay(2000);
  mySerial2.print(String("") + "main.t6.txt=\"--:--\"");
  end();

  mySerial2.print(String("") + "main.t7.txt=\"--:--\"");
  end();
}

void stateChange()
{
  speakFlag = 0;
}

void loop () {
  while (Serial.available() > 0)
  {
    String inputString = Serial.readStringUntil('\n');
    //检测json数据是否完整
    int jsonBeginAt = inputString.indexOf("{");
    int jsonEndAt = inputString.lastIndexOf("}");
    if (jsonBeginAt != -1 && jsonEndAt != -1)
    {
      //净化json数据
      inputString = inputString.substring(jsonBeginAt, jsonEndAt + 1);
      deserializeJson(readJson, inputString);
      if (readJson["FT_H"])
      {
        speakFlag = 1;
        Hour_1 = (int)readJson["FT_H"];
        Min_1 = (int)readJson["FT_M"];
        if (First == 0) {
          mySerial2.print(String("") + "main.t6.txt=\"" + Hour_1 + ":" + Min_1 + "\"");
          end();
        }

      }
      else if (readJson["ST_H"])
      {
        speakFlag = 1;
        Hour_2 = (int)readJson["ST_H"];
        Min_2 = (int)readJson["ST_M"];
        if (First == 1 && Second == 0) {
          mySerial2.print(String("") + "main.t6.txt=\"" + Hour_2 + ":" + Min_2 + "\"");
          end();
        }

      }
      else if (readJson["TT_H"])
      {
        speakFlag = 1;
        Hour_3 = (int)readJson["TT_H"];
        Min_3 = (int)readJson["TT_M"];
        if (First == 1 && Second == 1 && Third == 0) {
          mySerial2.print(String("") + "main.t6.txt=\"" + Hour_3 + ":" + Min_3 + "\"");
          end();
        }
      }
    }
  }

  //上传数据
  if (millis() - lastUpdateTime > updateInterval)
  {
    sendJsonData();
    lastUpdateTime = millis();
  }
  
  DateTime now = RTC.now();
  if (Hour_1 != now.hour() && Min_1 != now.minute() && Hour_2 != now.hour() && Min_2 != now.minute() && Hour_3 != now.hour() && Min_3 != now.minute())
    speakFlag = 1;
  if (Hour_1 == now.hour() && Min_1 == now.minute() && speakFlag == 1) {
    servo(servo_1, 180);
    SPEAK2();
    mySerial2.print(String("") + "main.t7.txt=\"" + Hour_1 + ":" + Min_1 + "\"");
    end();
    if (Hour_2 != 0 && Min_2 != 0) {
      mySerial2.print(String("") + "main.t6.txt=\"" + Hour_2 + ":" + Min_2 + "\"");
      end();
    }
    else {
      mySerial2.print(String("") + "main.t6.txt=\"--:--\"");
      end();
    }
    First = 1;
    Second = 0;
    Third = 0;
  }
  else if (Hour_2 == now.hour() && Min_2 == now.minute() && speakFlag == 1) {
    servo(servo_2, 160);
    SPEAK2();
    mySerial2.print(String("") + "main.t7.txt=\"" + Hour_2 + ":" + Min_2 + "\"");
    end();
    if (Hour_3 != 0 && Min_3 != 0) {
      mySerial2.print(String("") + "main.t6.txt=\"" + Hour_3 + ":" + Min_3 + "\"");
      end();
    }
    else {
      mySerial2.print(String("") + "main.t6.txt=\"--:--\"");
      end();
    }
    Second = 1;
  }
  else if (Hour_3 == now.hour() && Min_3 == now.minute() && speakFlag == 1) {
    servo(servo_3, 180);
    SPEAK2();
    mySerial2.print(String("") + "main.t7.txt=\"" + Hour_3 + ":" + Min_3 + "\"");
    end();
    if (Hour_1 != 0 && Min_1 != 0) {
      mySerial2.print(String("") + "main.t6.txt=\"" + Hour_1 + ":" + Min_1 + "\"");
      end();
    }
    else {
      mySerial2.print(String("") + "main.t6.txt=\"--:--\"");
      end();
    }
    Third = 1;
    First = 0;
    Second = 0;

  }

  //  Serial.print(now.year(), DEC);
  //  Serial.print('/');
  //  Serial.print(now.month(), DEC);
  //  Serial.print('/');
  //  Serial.print(now.day(), DEC);
  //  Serial.print(' ');
  //  Serial.print(now.hour(), DEC);
  //  Serial.print(':');
  //  Serial.print(now.minute(), DEC);
  //  Serial.print(':');
  //  Serial.println(now.second(), DEC);
  //打印时间
  mySerial2.print(String("") + "main.t2.txt=\"" + now.year() + '-' + now.month() + '-' + now.day() + ' ' + ' ' + "\"");
  end();
  mySerial2.print(String("") + "main.t0.txt=\"" + now.hour() + ':' + now.minute() + "\"");
  end();


  //体温测量
  TC = mlx.readObjectTempC();
  //  Serial.print("Object = ");
  //  Serial.print(mlx.readObjectTempC());
  //  Serial.println("*C");
  tem = mlx.readObjectTempC();
  Temp = mlx.readObjectTempC() * 100;
  tem_2 = Temp % 10;
  tem_1 = Temp / 10 % 10;

  mySerial2.print(String("") + "main.t4.txt=\"" + mlx.readObjectTempC() + "\""); //温度
  end();

  if (tem > 35 & tem < 38) {
    SPEAK();
  }

  //心率测量
  long irValue = particleSensor.getIR();
  int Value = irValue / 1000;
  if (irValue > 50000)
  {
    if (Value != lastValue)
    {
      delta = millis() - lastBeat;
      lastBeat = millis();
      lastValue = Value;
    }
    else
    {
      int beats = 60000 / (delta + 150);
      if (beats < 120 && beats > 70)
      {
        beatAvg = beats;
        //Serial.print("beats = ");
        //Serial.println(beats);
      }
    }
  }
  else
  {
    beatAvg = 0;
  }
  //Serial.print("beatAvg = ");
  //Serial.println(beatAvg);

  mySerial2.print(String("") + "page3.t1.txt=\"" + beatAvg + "\""); //
  end();


  //烟雾检测及报警
  state = digitalRead(GAS);
  //  Serial.print("GAS=");
  //  Serial.println(state);
  if (!state) {
    digitalWrite(BUZZER, HIGH);
    delay(2000);
    digitalWrite(BUZZER, LOW);
  }
  else
    digitalWrite(BUZZER, LOW);



  //  if (time1 == 1) {
  //    servo(1, 180);
  //    SPEAK2();
  //  }
  //  else if (time2 == 1) {
  //    servo(2, 180);
  //    SPEAK2();
  //  }
  //  else if (time2 == 1) {
  //    servo(2, 180);
  //    SPEAK2();
  //  }

}







//自己写的舵机控制函数
void servo(int pin, int angle) { //定义一个脉冲函数
  //发送50个脉冲
  for (int i = 0; i < 50; i++) {
    int pulsewidth = (angle * 11) + 500; //将角度转化为500-2480的脉宽值
    digitalWrite(pin, HIGH);   //将舵机接口电平至高
    delayMicroseconds(pulsewidth);  //延时脉宽值的微秒数
    digitalWrite(pin, LOW);    //将舵机接口电平至低
    delayMicroseconds(20000 - pulsewidth);
  }
  delay(100);
}


//自己写的舵机控制函数
void servo(int angle) { //定义一个脉冲函数
  //发送50个脉冲
  for (int i = 0; i < 50; i++) {
    int pulsewidth = (angle * 11) + 500; //将角度转化为500-2480的脉宽值
    digitalWrite(11, HIGH);   //将舵机接口电平至高
    delayMicroseconds(pulsewidth);  //延时脉宽值的微秒数
    digitalWrite(11, LOW);    //将舵机接口电平至低
    delayMicroseconds(20000 - pulsewidth);
  }
  delay(100);
}





void SPEAK()
{
  /****************需要发送的文本**********************************/
  sprintf(utf8str, "当前体温为%d点%d %d摄氏度", tem, tem_1, tem_2);
  unsigned char unicstr[100]; //输出 unicode 编码字符串
  int utf8_to_unicode(unsigned char *pUTF8, unsigned char *pUNIC);
  unsigned int length;
  unsigned char headOfFrame[5]; //定义数据帧头
  unsigned char ecc = 0 ; //定义校验字节
  unsigned int i = 0;


  length = utf8_to_unicode(utf8str, unicstr); //utf8 编码转换成 unicode 编码，并返回
  //unicode 字符数
  headOfFrame[0] = 0xFD ; //构造帧头 FD
  headOfFrame[1] = length >> 8 ; //构造数据区长度的高字节
  headOfFrame[2] = (length + 3) & 0xFF; //构造数据区长度的低字节
  headOfFrame[3] = 0x01; //构造命令字：合成播放命令
  headOfFrame[4] = 0x03 ; //构造命令参数：编码格式为 Unicode



  ecc = 0;
  for (i = 0; i < 5; i++) //依次发送构造好的 5 个帧头字节
  {
    ecc = ecc ^ (headOfFrame[i]); //对发送的字节进行异或校验
    mySerial1.write(headOfFrame[i]);
  }
  for (i = 0; i < length; i++) //依次发送待合成的文本数据
  {
    ecc = ecc ^ (unicstr[i]); //对发送的字节进行异或校验
    mySerial1.write(unicstr[i]);
    //Serial.println(unicstr[i], HEX);
  }
  mySerial1.write(ecc); //最后发送校验字节

  //delay(7000);

}





void SPEAK2()
{
  /****************需要发送的文本**********************************/
  sprintf(utf8str, "吃药时间到");
  unsigned char unicstr[100]; //输出 unicode 编码字符串
  int utf8_to_unicode(unsigned char *pUTF8, unsigned char *pUNIC);
  unsigned int length;
  unsigned char headOfFrame[5]; //定义数据帧头
  unsigned char ecc = 0 ; //定义校验字节
  unsigned int i = 0;


  length = utf8_to_unicode(utf8str, unicstr); //utf8 编码转换成 unicode 编码，并返回
  //unicode 字符数
  headOfFrame[0] = 0xFD ; //构造帧头 FD
  headOfFrame[1] = length >> 8 ; //构造数据区长度的高字节
  headOfFrame[2] = (length + 3) & 0xFF; //构造数据区长度的低字节
  headOfFrame[3] = 0x01; //构造命令字：合成播放命令
  headOfFrame[4] = 0x03 ; //构造命令参数：编码格式为 Unicode



  ecc = 0;
  for (i = 0; i < 5; i++) //依次发送构造好的 5 个帧头字节
  {
    ecc = ecc ^ (headOfFrame[i]); //对发送的字节进行异或校验
    mySerial1.write(headOfFrame[i]);
  }
  for (i = 0; i < length; i++) //依次发送待合成的文本数据
  {
    ecc = ecc ^ (unicstr[i]); //对发送的字节进行异或校验
    mySerial1.write(unicstr[i]);
    //Serial.println(unicstr[i], HEX);
  }
  mySerial1.write(ecc); //最后发送校验字节

  delay(4000);

}



void end()
{
  mySerial2.write(0XFF);       //结束符
  mySerial2.write(0XFF);
  mySerial2.write(0XFF);
}


void sendJsonData() {
  sendJson["ID"] = ID;
  sendJson["TC"] = TC;
  sendJson["BE"] = beatAvg;
  sendJson["GA"] = state;
  serializeJson(sendJson, Serial);
  Serial.print("\n");
}




int utf8_to_unicode(unsigned char *pUTF8, unsigned char *pUNIC)
{
  //SYN6288 中 unicode 编码采用大端模式
  // b1 表示 UTF-8 编码的 pInput 中的高字节, b2 表示次高字节, ...
  unsigned char b1, b2, b3, b4;
  int utfbytes = 0;
  while ( *pUTF8 != '\0')
  {
    b1 = *pUTF8;
    if ( (b1 & 0x80) == 0x0) // utf8 - one byte
    {
      utfbytes = utfbytes + 2;
      *pUNIC = 0x00;
      *(pUNIC + 1) = b1;
      pUTF8++;
      pUNIC = pUNIC + 2;
    }
    else if ( (b1 & 0xE0) == 0xC0) // utf8 - two byte
    {
      utfbytes = utfbytes + 2;
      b1 = *pUTF8;
      b2 = *(pUTF8 + 1);
      if ( (b2 & 0xC0) != 0x80 )
        return 0;
      *pUNIC = (b1 >> 2) & 0x07;
      *(pUNIC + 1) = (b1 << 6) + (b2 & 0x3F);
      pUTF8 = pUTF8 + 2;
      pUNIC = pUNIC + 2;
    }
    else if ( (b1 & 0xF0) == 0xE0) // utf8 - three byte
    {
      utfbytes = utfbytes + 2;
      b1 = *pUTF8;
      b2 = *(pUTF8 + 1);
      b3 = *(pUTF8 + 2);
      if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80) )
        return 0;
      *pUNIC = (b1 << 4) + ((b2 >> 2) & 0x0F);
      *(pUNIC + 1) = (b2 << 6) + (b3 & 0x3F);
      pUTF8 = pUTF8 + 3;
      pUNIC = pUNIC + 2;
    }
    else if ( (b1 & 0xF8) == 0xF0) // utf8 - four byte
    {
      utfbytes = utfbytes + 3;
      b1 = *pUTF8;
      b2 = *(pUTF8 + 1);
      b3 = *(pUTF8 + 2);
      b4 = *(pUTF8 + 3);
      if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80) || ((b4 & 0xC0) != 0x80) )
        return 0;
      *pUNIC = ((b1 << 2) & 0x1C) + ((b2 >> 4) & 0x03);
      *(pUNIC + 1) = (b2 << 4) + ((b3 >> 2) & 0x0F);
      *(pUNIC + 2) = (b3 << 6) + (b4 & 0x3F);
      pUTF8 = pUTF8 + 4;
      pUNIC = pUNIC + 3;
    }
  }
  *pUNIC = '\0';
  return utfbytes;
}